﻿
using System;
using System.Diagnostics;
using System.Windows.Forms;
using n_AVRdudeSetForm;
using System.IO;

namespace n_AVRdude
{
public static class AVRdude
{
	public static AVRdudeSetForm myAVRdudeSetForm;
	
	public static bool tempShowError = false;
	public static bool tempISP = false;
	public static string BoardType;
	public static string PortName;
	
	static int PerTime;
	
	public delegate void deleProgressStep( int Max, int Current );
	public static deleProgressStep ProgressStep;
	
	public delegate void deleISPStep( string Mes );
	public static deleISPStep ISPStep;
	
	public static bool OK;
	
	public static string OutputResult;
	public static string ErrorMes;
	public static string ErrorMes1;
	
	public static bool NanoisIDEType = false;
	
	public static bool isIDE = false;
	
	public static bool NanoNew;
	
	public static bool isNano;
	
	
	//初始化
	public static void Init()
	{
		myAVRdudeSetForm = new AVRdudeSetForm();
		
		BoardType = null;
		PortName = null;
		
		PerTime = 20;
	}
	
	//下载
	public static bool Download( string Path, bool HexFile, bool ShowSetForm, bool first )
	{
		OK = false;
		
		string FilePath = "\"" + Path + "\"";
		string Baud = null;
		string Chip = null;
		string AVRdudePath = null;
		
		isNano = false;
		
		if( BoardType == "2560" ) {
			Chip = "atmega2560";
			AVRdudePath = "AVRdude"; //2560
		}
		else if( BoardType == "644" ) {
			Chip = "m644p";
			AVRdudePath = "AVRdude"; //2560
		}
		else {
			Chip = "m328p";
			AVRdudePath = "AVRdude";
		}
		
		if( BoardType == "UNO" || BoardType == "2560" || BoardType == "644" ) {
			Baud = "115200";
		}
		else if( BoardType == "NANO" || BoardType == "DRPI" ) {
			
			if( NanoisIDEType || !first ) {
				Baud = "115200";
			}
			else {
				Baud = "57600";
			}
			//禁用自动切换，总是读取系统配置决定波特率
			if( NanoNew ) {
				Baud = "115200";
			}
			else {
				Baud = "57600";
			}
			
			isNano = true;
		}
		else {
			MessageBox.Show( "暂不支持下载程序到此型号的 Arduino 电路板: " + BoardType );
			return false;
		}
		if( ShowSetForm ) {
			string r = myAVRdudeSetForm.Run( Chip, Baud );
			if( r == null ) {
				//MessageBox.Show( "您取消了本次下载" );
				if( !HexFile ) {
					System.IO.File.Delete( Path );
				}
				return false;
			}
			string[] cut = r.Split( ' ' );
			PortName = cut[0];
			Chip = cut[1];
			Baud = cut[2];
		}
		/*
		//检测端口是否可以打开
		if( myAVRdudeSetForm.checkBoxAutoCheck.Checked ) {
			System.IO.Ports.SerialPort p;
			try {
				p = new System.IO.Ports.SerialPort( Port );
				p.BaudRate = 9600;
				p.DataBits = 8;
				p.Parity = System.IO.Ports.Parity.None;
				p.StopBits = System.IO.Ports.StopBits.One;
				p.ReadTimeout = 1;
				p.Open();
			}
			catch {
				MessageBox.Show( "串口" + Port + "打开失败导致无法下载, 请检查您是否有其他串口软件也在占用此串口, 是的话请关闭这些软件并重新点击下载按钮. 如无软件占用串口, 请检查您的数据线是否和电脑连接.", "下载失败提示" );
				myAVRdudeSetForm.checkBoxHide.Checked = false;
				return false;
			}
			p.Close();
			System.Threading.Thread.Sleep( 500 );
		}
		*/
		Process Proc = new Process();
		Proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
		Proc.StartInfo.UseShellExecute = false;
		Proc.StartInfo.CreateNoWindow = true;
		Proc.StartInfo.RedirectStandardOutput = true;
		Proc.StartInfo.RedirectStandardError = true;
		
		//Proc.StartInfo.WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory + @"Resource\tools\" + AVRdudePath;
		
		Proc.StartInfo.FileName = AppDomain.CurrentDomain.BaseDirectory + @"Resource\tools\" + AVRdudePath + @"\avrdude.exe";//调用汇编命令
		
		
		if( Chip == "m328p" ) {
			//string Path = "\"C:\\Users\\dell\\Desktop\\我的小程序0.HEX\"";
			//Info.Arguments = @"-F -v -pm328p -cstk500v1 -P\\.\COM4 -b115200 -D -Uflash:w:" + Path + ":i";
			//-F -v -pm328p -cstk500v1 -P\\.\COM4 -b115200 -D -Uflash:w:"C:\Users\dell\Desktop\我的小程序0.HEX":i
			
			//旧版的 AVRdude 用这个命令行
			//Proc.StartInfo.Arguments = "-F -v -p" + Chip + @" -cstk500v1 -P\\.\" + Port + " -b" + Baud + " -D -Uflash:w:" + FilePath + ":i";
			
			Proc.StartInfo.Arguments = "-v -p" + Chip + " -carduino -P" + PortName + " -b" + Baud + " -D -Uflash:w:" + FilePath + ":i";
		}
		else if( Chip == "m644p" ) {
			//"-v -patmega644p -carduino -PCOM23 -b115200 -D -Uflash:w:C:\\Users\\dell\\AppData\\Local\\Temp\\build723f27e600b7276f0c2fa8df26ea87c3.tmp/Blink.ino.hex:i";
			Proc.StartInfo.Arguments = "-v -p" + Chip + " -carduino -P" + PortName + " -b" + Baud + " -D -Uflash:w:" + FilePath + ":i";
		}
		//这里是2560
		else {
			// -v -patmega2560 -cwiring -PCOM6 -b115200 -D -Uflash:w:C:\Users\cap_gpu\AppData\Local\Temp\build4587197968020176821.tmp/sketch_may28a.cpp.hex:i		
			//Proc.StartInfo.Arguments = @"-v -patmega2560 -cwiring -PCOM6 -b115200 -D -Uflash:w:C:\Users\cap_gpu\AppData\Local\Temp\build4587197968020176821.tmp/Blink.cpp.hex:i";
			Proc.StartInfo.Arguments = "-v -p" + Chip + " -cwiring -P" + PortName + " -b" + Baud + " -D -Uflash:w:" + FilePath + ":i";
		}
		
		OutputResult = "";
		
		Proc.Start();
		Proc.BeginOutputReadLine();
		Proc.BeginErrorReadLine();
		Proc.OutputDataReceived += new DataReceivedEventHandler(DataHandler);
		Proc.ErrorDataReceived += new DataReceivedEventHandler(EDataHandler);
		
		int i = 0;
		
		if( ISPStep != null ) {
			ISPStep( "下载程序..." );
		}
		while( !Proc.HasExited ) {
			System.Windows.Forms.Application.DoEvents();
			if( ProgressStep != null ) {
				int x = i * PerTime;
				if( x > n_ATMEGA_Assembler.ATMEGA_Assembler.Address ) {
					x = n_ATMEGA_Assembler.ATMEGA_Assembler.Address;
				}
				ProgressStep( n_ATMEGA_Assembler.ATMEGA_Assembler.Address, x );
			}
			i++;
		}
		int tPerTime = n_ATMEGA_Assembler.ATMEGA_Assembler.Address / i;
		if( tPerTime != 0 ) {
			PerTime = tPerTime;
		}
		
		ErrorMes = null;
		OK = true;
		
		if( OutputResult.IndexOf( "error" ) != -1 ) {
			ErrorMes = "串口无回应数据, 请确保:\n";
			ErrorMes1 = "1: 软件界面主板型号和实物主板型号相同\n2: 主板连接到电脑USB并选择了正确的串口号";
			myAVRdudeSetForm.comboBoxPort.SelectedIndex = -1;
		}
		//2019.12.6 德国电脑报此错误
		if( OutputResult.IndexOf( "failed" ) != -1 ) {
			ErrorMes = "可能是路径异常:\n";
			ErrorMes1 = "1: 如果是国外的电脑建议lab文件名和路径不要含有中文\n2: 如还无法解决请联系我";
			myAVRdudeSetForm.comboBoxPort.SelectedIndex = -1;
		}
		if( OutputResult.IndexOf( "not in sync" ) != -1 ) {
			ErrorMes = "串口返回协议错误, 请确保:\n";
			ErrorMes1 = "1: 软件界面主板型号和实物主板型号相同\n2: 主板连接到电脑USB并选择了正确的串口号";
		}
		
		if( ErrorMes != null ) {
			if( BoardType == "NANO" && Baud == "57600" ) {
				ErrorMes1 += "\n可以尝试用115200波特率下载（旧版为57600）";
			}
			if( BoardType == "NANO" && Baud == "115200" ) {
				ErrorMes1 += "\n可以尝试用57600波特率下载（新版为115200）";
			}
		}
		
		if( OutputResult.IndexOf( "can't open device" ) != -1 ) {
			ErrorMes = "指定的串口号打不开, 请选择正确的串口号或关闭其他占用此串口的程序";
			ErrorMes1 = "(每次插拔数据线到不同的电脑USB口, 串口号会改变)";
			myAVRdudeSetForm.comboBoxPort.SelectedIndex = -1;
			return true;
		}
		if( OutputResult.IndexOf( "out of range" ) != -1 ) {
			ErrorMes = "程序已超出芯片最大空间!";
			ErrorMes1 = "请尝试删除一些模块和指令再进行下载, 或者采用多个arduino主板联合实现功能";
		}
		if( OutputResult.IndexOf( "programmer is not responding" ) != -1 ) {
			ErrorMes = "*下载器没有回应!";
			ErrorMes1 = "程序可能下载失败, 建议重新点击一次下载按钮";
		}
		if( OutputResult.IndexOf( "programmer is out of sync" ) != -1 ) {
			ErrorMes = "*下载器协议未同步!";
			ErrorMes1 = "程序可能下载失败, 建议重新点击一次下载按钮";
		}
		System.Threading.Thread.Sleep( 500 );
		if( !HexFile ) {
			System.IO.File.Delete( Path );
		}
		
		if( ErrorMes == null && BoardType == "NANO" && Baud == "115200" ) {
			NanoisIDEType = true;
		}
		
		if( tempShowError ) {
			//string ss1 = OutputResult.Remove( 0, OutputResult.Length / 2 );
			//string ss2 = OutputResult.Remove( OutputResult.Length / 2 );
			//MessageBox.Show( ss2 );
			//MessageBox.Show( ss1 );
		}
		
		return false;
	}
	
	private static void DataHandler(object sendingProcess, DataReceivedEventArgs e)
	{
		if(!String.IsNullOrEmpty(e.Data)) {
			OutputResult += "O:" + e.Data + "\n";
		}
	}
	
	private static void EDataHandler(object sendingProcess, DataReceivedEventArgs e)
	{
		if(!String.IsNullOrEmpty(e.Data)) {
			OutputResult += "E:" + e.Data + "\n";
		}
	}
}
}



